home *** CD-ROM | disk | FTP | other *** search
- /*==============================================================================
-
- FICHERO: GIF.C
-
- AUTOR: ANTONIO LADESA JURADO
-
- FECHA: 24/6/94
-
- DESCRIPCION:
-
- Fichero que contiene las estructuras, constantes, variables y funciones
- internas y externas para el procesamiento de ficheros GIF.
-
- ==============================================================================*/
-
-
- /*---- MODULOS USADOS --------------------------------------------------------*/
-
- #include <stdio.h>
- #include <string.h>
- #include <conio.h>
- #include <dos.h>
- #include <alloc.h>
- #include <stdlib.h>
- #include <dir.h>
- #include <io.h>
-
- #include "global.h"
- #include "memoria.h"
- #include "video.h"
- #include "color.h"
- #include "gif.h"
- #include "error.h"
-
- /*---- ESTRUCTURAS, CONSTANTES Y VARIABLES LOCALES AL MODULO -----------------*/
-
- /* cabecera global de un GIF */
- typedef struct
- {
- char id[6];
- int ancho_pantalla;
- int alto_pantalla;
- char bandera_global;
- char color_fondo;
- char cero;
- }CABgif;
-
- /* estructura local */
- typedef struct
- {
- int x0;
- int y0;
- int ancho;
- int alto;
- char bandera_local;
- }GIFlocal;
-
- /* datos de entrada a la función de escritura de ficheros GIF */
- /* escrita en ensamblador. Módulo GIFASM.ASM */
- typedef struct
- {
- unsigned int ancho_pantalla;
- unsigned int alto_pantalla;
- unsigned int izda_imagen;
- unsigned int arriba_imagen;
- unsigned int ancho_imagen;
- unsigned int alto_imagen;
- unsigned int fondo;
- unsigned int bits;
- unsigned long tam_imagen;
- char *paleta;
- char *origen;
- char *destino;
- }GIFdatos;
-
-
- /* variables de control de lineas */
- int x,y;
- /* buffer para la línea leida */
- char linea[ANCHO_MAXIMO];
-
- /* puntero a fichero */
- FILE *f;
-
- /* tablas y variables para la gestión del modo entrelazado */
- static int incremento[5]={8,8,4,2,0};
- static int inicio[5]={0,4,2,1,0};
- int entrelazado;
- int paso;
-
- /* variables usadas en la descompresión LZW */
- static char mascara[9] = {0,1,3,7,0xf,0x1f,0x3f,0x7f,0xff};
- int BufferBits,ContadorBits,ContadorBuffer,LongitudPixel;
-
- /* tablas LZW */
- char *LZWpila,*LZWultimo,*LZWprimero;
- int *LZWenlace;
- /* indices a las tablas LZW */
- int SiguienteLimite,SiguienteCodigo;
-
- /*---- DEFINICION DE LAS FUNCIONES INTERNAS ----------------------------------*/
-
- IMAGEN *GIFleerImagen(IMAGEN *c);
- IMAGEN *GIFleerCabecera(IMAGEN *c,char *nombre);
- IMAGEN *LZWleer(IMAGEN *c,int CodigoInicio,int LongitudPixel);
- IMAGEN *GIFextraerPixel(IMAGEN *c,int codigo, int LongitudPixel);
- IMAGEN *GIFponerPixel(IMAGEN *c,int pixel);
- void GIFliberar(void);
-
- int ExtraerCodigo(int LongitudCodigo);
- int LeerCodigo(int LongitudCodigo);
- int leerByte(void);
-
- void InicializarTabla(int CodigoLimpiar);
- void InsertarCodigo(int codigo,int AnteriorCodigo,int *csizeptr);
-
- /* función de compresión LZW, en ensamblador. Módulo GIFASM.ASM */
- extern int LZWescribir(GIFdatos *);
-
- /*---- CODIFICACION DE LAS FUNCIONES OFRECIDAS -------------------------------*/
-
-
- /*---- FUNCION: extern IMAGEN *GIFcargar(char *nombre,IMAGEN *c) ---------------
-
- Descripción:
-
- Esta función carga en memoria una imagen de tipo GIF.
-
- Parámetros:
-
- char *nombre : nombre del fichero a cargar
- IMAGEN *c : puntero a estructura que alberga la imagen
-
- Retorno:
-
- Puntero a la estructura de la imagen o NULL si hubo error
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- extern IMAGEN *GIFcargar(char *nombre,IMAGEN *c)
- {
- /* abrir fichero */
- if((f=fopen(nombre,"rb"))!=NULL)
- {
- /* leer cabecera GIF */
- if((c=GIFleerCabecera(c,nombre))!=NULL)
- /* leer imagen */
- c = GIFleerImagen(c);
- fclose(f);
- }
- else
- {
- ERRORponer(ERRapertura);
- return(NULL);
- }
- return(c);
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*---- FUNCION: extern int *GIFsalvar(char *nombre,IMAGEN *c) ------------------
-
- Descripción:
-
- Esta función salva en disco una imagen con formato GIF.
-
- Parámetros:
-
- char *nombre : nombre del fichero a salvar
- IMAGEN *c : puntero a estructura que alberga la imagen
-
- Retorno:
-
- - 0 si hay error
- - 1 en caso contrario
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- extern int GIFsalvar(char *nombre,IMAGEN *c)
- {
- /* estructura para la función de compresión */
- GIFdatos cgif;
- /* fichero temporal */
- char origen[MAXDIR];
- FILE *temp;
- /* buffer */
- char p[ANCHO_MAXIMO];
- /* contador */
- int i;
-
- /* solo ficheros VGA 256 colores */
- if(c->colores != 256)
- c = EscalarColores(c,256);
-
- /* crea fichero temporal para guardar imagen */
- strcpy(origen,"gif.tmp");
-
- /* abrir fichero */
- if((temp = fopen(origen,"wb"))==NULL)
- {
- ERRORponer(ERRapertura);
- return(0);
- }
-
- /* escribe datos de la imagen en fichero temporal */
- for(i = 0; i < c->alto;++i)
- {
- MEMleer(p,i,c);
- fwrite(p,c->bytes,1,temp);
- }
- fclose(temp);
-
- /* rellena estructura para la compresión */
- cgif.ancho_pantalla=c->ancho;
- cgif.alto_pantalla=c->alto;
- cgif.izda_imagen=0;
- cgif.arriba_imagen=0;
- cgif.ancho_imagen=c->ancho;
- cgif.alto_imagen=c->alto;
- cgif.fondo=0;
- cgif.bits = 8;
- cgif.tam_imagen = (long)c->ancho*(long)c->alto;
- cgif.paleta = c->paleta;
- cgif.origen = origen;
- cgif.destino = nombre;
- /* comprime */
- i = LZWescribir(&cgif);
- /* borra fichero temporal */
- unlink(origen);
- /* detección errores */
- if(!i)
- return(1);
- else
- {
- ERRORponer(ERRescritura);
- return(0);
- }
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*---- CODIFICACION DE LAS FUNCIONES INTERNAS --------------------------------*/
-
-
- /*---- FUNCION: IMAGEN *GIFleerCabecera(IMAGEN *c,char *nombre) ----------------
-
- Descripción:
-
- Esta función reserva memoria para la imagen y lee la cabecera del fichero
- GIF.
-
- Parámetros:
-
-
- IMAGEN *c : puntero a estructura que alberga la imagen
- char *nombre : nombre del fichero a cargar
-
- Retorno:
-
- Puntero a la estructura de la imagen o NULL si hubo error
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- IMAGEN *GIFleerCabecera(IMAGEN *c,char *nombre)
- {
- /* cabecera global */
- CABgif cab;
- /* datos locales */
- GIFlocal img;
- /* bandera de proceso de imagen */
- char proceso=0;
- /* código leido del fichero */
- int codigo;
-
- /* leer cabecera global */
- if(fread((char *)&cab,sizeof(CABgif),1,f)!=sizeof(CABgif))
- {
- /* comprobar que es GIF */
- if(memcmp(cab.id,"GIF",3) || cab.cero)
- {
- ERRORponer(ERRnoTratado);
- return(NULL);
- }
- }
- else
- {
- ERRORponer(ERRlectura);
- return(NULL);
- }
-
- /* reservar memoria para cabecera, paleta y tablas */
- if((c = MEMreservarCAB(c)) != NULL)
- if((LZWpila = (char *)malloc(4096)) != NULL)
- if((LZWultimo = (char *)malloc(4096)) != NULL)
- if((LZWprimero = (char *)malloc(4096)) != NULL)
- if((LZWenlace = (int *)malloc(4096*sizeof(int))) != NULL)
- {
- /* obtener longitud del pixel y número de colores */
- LongitudPixel = ((cab.bandera_global & 0x07)+1);
- c->colores = 1 << LongitudPixel;
-
- /* cargar cabecera estandar de la imagen */
- strcpy(c->nombre,nombre);
- c->ancho = cab.ancho_pantalla;
- c->alto = cab.alto_pantalla;
- c->bytes = cab.ancho_pantalla;
- c->formato = GIF;
- c->modo = VIDEOvga;
- c->haypaleta = CIERTO;
-
- /* si hay paleta global */
- if(cab.bandera_global & 0x80)
- /* leerla */
- if(fread((char *)c->paleta,1,c->colores*3,f) != c->colores*3)
- {
- GIFliberar();
- c = MEMliberar(c);
- return(c);
- }
-
- /* procesar los datos de la imagen */
- while(!proceso)
- {
- /* leer código */
- codigo = fgetc(f);
- switch(codigo)
- {
- /* código de imagen */
- case ',':
- /* leer datos locales */
- fread((char *)&img,sizeof(img),1,f);
- entrelazado = (0x40 & img.bandera_local);
- c->ancho = img.ancho;
- c->alto = img.alto;
- c->bytes = img.ancho;
-
- /* si hay paleta local, se lee y se usa, si no, se usa la global */
- if(0x80 & img.bandera_local)
- {
- /* obtener longitud del pixel y número de colores */
- LongitudPixel = ((img.bandera_local & 0x07)+1);
- c->colores = 1 << LongitudPixel;
- /* leer paleta local */
- if(fread((char *)c->paleta,1,c->colores*3,f) != c->colores*3)
- {
- GIFliberar();
- c = MEMliberar(c);
- return(c);
- }
- }
- /* ya están los datos de la imagen, incrementar y salir */
- proceso++;
- break;
-
- /* extension, no tratada, se lee completa y continúa el proceso */
- case '!':
- {
- int contador;
-
- codigo = fgetc(f);
- for(;;)
- {
- contador = fgetc(f);
- if(!contador)
- break;
- while(contador--)
- codigo = fgetc(f);
- }
- }
- break;
-
- default:
- GIFliberar();
- c = MEMliberar(c);
- ERRORponer(ERRlectura);
- return(c);
- }
- }
- }
- else
- /* si no hay memoria para todo, liberar */
- {
- GIFliberar();
- c = MEMliberar(c);
- ERRORponer(ERRnoImagen);
- ERRORver();
- return(c);
- }
- return(c);
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*---- FUNCION: IMAGEN *GIFleerImagen(IMAGEN *c) -------------------------------
-
- Descripción:
-
- Esta función carga en memoria una imagen de tipo GIF.
-
- Parámetros:
-
- IMAGEN *c : puntero a estructura que alberga la imagen
-
- Retorno:
-
- Puntero a la estructura de la imagen
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- IMAGEN *GIFleerImagen(IMAGEN *c)
- {
- int CodigoInicio;
- /* leer código de inicio */
- CodigoInicio = fgetc(f);
- /* descompactar imagen */
- LZWleer(c,CodigoInicio,LongitudPixel);
- /* leer fin fichero */
- fgetc(f);
- /* liberar memoria usada por las tablas LZW */
- GIFliberar();
- return(c);
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*---- FUNCION: void GIFliberar(void) ------------------------------------------
-
- Descripción:
-
- Esta función libera la memoria dinámica reservada para las tablas LZW.
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- void GIFliberar(void)
- {
- /* liberar tablas LZW */
- if(LZWpila!=NULL) free(LZWpila);
- if(LZWultimo!=NULL) free(LZWultimo);
- if(LZWprimero!=NULL)free(LZWprimero);
- if(LZWenlace!=NULL) free(LZWenlace);
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*---- FUNCION: IMAGEN *GIFponerPixel(IMAGEN *c,int pixel) ---------------------
-
- Descripción:
-
- Esta función lleva un pixel a su correspondiente posición x,y en memoria.
- Se actualizan las variables globales x,y.
-
- Parámetros:
-
- IMAGEN *c : puntero a estructura que alberga la imagen
-
- int pixel: color de pixel.
-
- Retorno:
-
- Puntero a la estructura de la imagen
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- IMAGEN *GIFponerPixel(IMAGEN *c,int pixel)
- {
- /* poner pixel en la línea */
- linea[x++]=pixel;
-
- /* si la línea esta completa */
- if(x == c->ancho)
- {
- /* mandar línea a la memoria */
- MEMescribir(linea,y,c);
- x = 0;
- /* si hay modo entrelazado, calcular siguiente linea */
- if(entrelazado)
- {
- y += incremento[paso];
- if(y >= c->alto)
- y = inicio[++paso];
- }
- else
- ++y;
- }
- return(c);
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*-- FUNCION: IMAGEN *GIFextraerPixel(IMAGEN *c,int codigo,int LongitudPixel) --
-
- Descripción:
-
- Esta función extrae una sucesión de pixels de la tabla.
- Estos pixels son los contenidos en código.
-
- Parámetros:
-
- IMAGEN *c : puntero a estructura que alberga la imagen
- int codigo: código leído y descomprimido por el algoritmo
- int LongitudPixel: longitud del pixel.
-
- Retorno:
-
- Puntero a la estructura de la imagen
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- IMAGEN *GIFextraerPixel(IMAGEN *c,int codigo, int LongitudPixel)
- {
- /* pixels totales a extraer */
- int contador = 0;
- /* puntero auxiliar */
- char *p;
-
- /* puntero al inicio de la pila */
- p = LZWpila;
- do
- {
- /* introducir dato en la pila */
- *p = LZWultimo[codigo];
- p++;
- contador++;
- /* obtener siguiente dato usando la tabla de enlace */
- codigo = LZWenlace[codigo];
- }
- while(codigo != -1);
-
- /* llevar pixels a la memoria */
- if(LongitudPixel == 1)
- {
- do
- {
- p--;
- c=GIFponerPixel(c,*p & 0x0001);
- c=GIFponerPixel(c,(*p & 0x00ff) >> 1);
- }
- while(--contador);
- }
- else
- {
- do
- {
- p--;
- c=GIFponerPixel(c,*p & 0x00ff);
- }
- while(--contador);
- }
- return(c);
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*-- FUNCION: IMAGEN *LZWleer(IMAGEN *c,int CodigoInicio,int LongitudPixel) ----
-
- Descripción:
-
- Esta función reproduce el algoritmo de descompresión LZW.
- Lee códigos del fichero y los introduce en la tabla.
- También se encarga de enviar los pixels a la memoria.
-
- Parámetros:
-
- IMAGEN *c : puntero a estructura que alberga la imagen
- int CodigoInicio: Primer código leido.
- int LongitudPixel: longitud del pixel.
-
- Retorno:
-
- Puntero a la estructura de la imagen
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- IMAGEN *LZWleer(IMAGEN *c,int CodigoInicio,int LongitudPixel)
- {
- /* código leido */
- int codigo;
- /* código leido anteriormente */
- int AnteriorCodigo;
- /* longitud del código */
- int LongitudCodigo;
- /* código de borrado */
- int CodigoLimpiar;
- /* código de fin */
- int CodigoFin;
-
- /* reservar memoria para la imagen */
- if((c = MEMreservar(c))==NULL)
- {
- c = MEMliberar(c);
- return(c);
- }
-
- /* inicializar variables */
- ContadorBuffer = 0;
- BufferBits = ContadorBits = 0;
- CodigoLimpiar= 1 << CodigoInicio;
- CodigoFin=CodigoLimpiar+1;
- LongitudCodigo=CodigoInicio+1;
- InicializarTabla(CodigoLimpiar);
- AnteriorCodigo= -1;
- paso =0;
- x = y = 0;
-
- while(1)
- {
- /* leer código */
- codigo = ExtraerCodigo(LongitudCodigo);
-
- /* si es código de borrado, inicializar la tabla */
- if(codigo == CodigoLimpiar)
- {
- /* inicializar la tabla de códigos */
- InicializarTabla(CodigoLimpiar);
- LongitudCodigo=CodigoInicio+1;
- AnteriorCodigo=-1;
- continue;
- }
- else
- /* si es código de final, terminar */
- if(codigo == CodigoFin)
- break;
- else
- /* si es código de imagen, insertarlo en la tabla */
- if(LZWenlace[codigo] != -2)
- {
- if(AnteriorCodigo != -1)
- InsertarCodigo(codigo,AnteriorCodigo,&LongitudCodigo);
- }
- else
- InsertarCodigo(AnteriorCodigo,AnteriorCodigo,&LongitudCodigo);
- /* tratar código, extrayendo pixels */
- c=GIFextraerPixel(c,codigo,LongitudPixel);
- AnteriorCodigo=codigo;
- }
- return(c);
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*-- FUNCION: int ExtraerCodigo(int LongitudCodigo) ----------------------------
-
- Descripción:
-
- Esta función lee del buffer de entrada un código de longitud
- LongitudCodigo bits.
-
- Parámetros:
-
- int LongitudCodigo: longitud del código en bits.
-
- Retorno:
-
- Código leído
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- int ExtraerCodigo(int LongitudCodigo)
- {
- /* si ocupa un solo byte */
- if(LongitudCodigo<=8)
- return(LeerCodigo(LongitudCodigo));
- /* si ocupa dos */
- return(LeerCodigo(8) | ((LeerCodigo(LongitudCodigo-8))<<8));
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*-- FUNCION: int LeerCodigo(int LongitudCodigo) -------------------------------
-
- Descripción:
-
- Esta función lee del buffer de entrada un código de 8 bits y lo
- devuelve ajustado LongitudCodigo bits.
-
- Parámetros:
-
- int LongitudCodigo: longitud del código en bits.
-
- Retorno:
-
- Código leído
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- int LeerCodigo(int LongitudCodigo)
- {
- /* código a devolver */
- int codigo;
- /* si no quedan bits leidos anteriormente, leer un byte */
- if(ContadorBits == 0)
- {
- BufferBits= leerByte();
- ContadorBits=8;
- }
- /* si quedan bits pero no hay suficientes, leer byte y ajustarlo */
- if(ContadorBits < LongitudCodigo)
- {
- BufferBits |= leerByte() << ContadorBits;
- ContadorBits +=8;
- }
- /* extraer LongitudCodigo bits del buffer */
- codigo = BufferBits & mascara[LongitudCodigo];
- ContadorBits -= LongitudCodigo;
- BufferBits = BufferBits >> LongitudCodigo;
- return(codigo);
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*-- FUNCION: int LeerByte(void) -----------------------------------------------
-
- Descripción:
-
- Esta función lee un byte del fichero procesando los paquetes en los
- que se encuentran los datos.
-
- Retorno:
-
- Byte leído del fichero.
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- int leerByte(void)
- {
- int dato;
- /* si se acabó el paquete, leer contador */
- if(ContadorBuffer==0)
- ContadorBuffer = fgetc(f);
- /* leer dato */
- dato = fgetc(f);
- /* decrementar contador */
- ContadorBuffer--;
- return(dato);
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*-- FUNCION: void InicializarTabla(int CodigoLimpiar) -------------------------
-
- Descripción:
-
- Esta función inicializa la tabla LZW con el código de borrado como límite
-
- Parámetros:
-
- int CodigoLimpiar: código de borrado.
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- void InicializarTabla(int CodigoLimpiar)
- {
- /* contador */
- int c=0;
- /* primer código libre en la tabla */
- SiguienteCodigo=CodigoLimpiar+2;
- /* límite para el código */
- SiguienteLimite=CodigoLimpiar << 1;
- while(c < CodigoLimpiar)
- {
- LZWprimero[c]=c;
- LZWultimo[c]=c;
- LZWenlace[c++]=-1;
- }
- while(c < 4096)
- LZWenlace[c++]= -2;
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-
-
- /*-- FUNCION: void InsertarCodigo(int NuevoCodigo, -------------
- int AnteriorCodigo,
- int *LongitudCodigo)
-
- Descripción:
-
- Esta función inserta un código en la tabla LZW.
-
- Parámetros:
-
- int NuevoCodigo: código a insertar.
- int AnteriorCodigo: código anterior.
- int *LongitudCodigo: longitud del código en bits.
-
- ---- CODIGO: -----------------------------------------------------------------*/
-
- void InsertarCodigo(int NuevoCodigo,int AnteriorCodigo,int *LongitudCodigo)
- {
- LZWenlace[SiguienteCodigo]=AnteriorCodigo;
- LZWultimo[SiguienteCodigo]=LZWprimero[NuevoCodigo];
- LZWprimero[SiguienteCodigo]=LZWprimero[AnteriorCodigo];
- /* si se hace pequeña, ampliar la longitud del código */
- if(++SiguienteCodigo == SiguienteLimite)
- if(*LongitudCodigo < 12)
- {
- (*LongitudCodigo)++;
- SiguienteLimite = SiguienteLimite << 1;
- }
- }
-
- /*---- FIN FUNCION -----------------------------------------------------------*/
-